package com.stone.redis.lock.service.impl;

import com.stone.redis.lock.domain.bo.LockInfo;
import com.stone.redis.lock.service.LockService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/**
 * 写锁实现
 *
 * @author Mr_wenpan@163.com 2021/07/27 11:03
 */
@Slf4j
public class WriteLockServiceImpl implements LockService {

    @Qualifier("lockRedissonClient")
    @Autowired
    private RedissonClient redissonClient;

    private final ThreadLocal<LockInfo> lockInfoThreadLocal = new ThreadLocal<>();

    @Override
    public void setLockInfo(LockInfo lockInfo) {
        lockInfoThreadLocal.set(lockInfo);
    }

    @Override
    public LockInfo getLockInfo() {
        return lockInfoThreadLocal.get();
    }

    @Override
    public void clearLockInfo() {
        lockInfoThreadLocal.remove();
    }

    @Override
    public boolean lock() {
        // 先从线程内部获取锁信息
        LockInfo lockInfo = lockInfoThreadLocal.get();
        try {
            // 通过锁名称获取锁对象
            RReadWriteLock rLock = redissonClient.getReadWriteLock(lockInfo.getName());
            // 依靠锁对象获取分布式锁
            return rLock.writeLock().tryLock(lockInfo.getWaitTime(), lockInfo.getLeaseTime(), lockInfo.getTimeUnit());
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public void releaseLock() {
        // 先从线程内部获取锁信息
        LockInfo lockInfo = lockInfoThreadLocal.get();
        // 通过锁名称获取锁对象
        RReadWriteLock rLock = redissonClient.getReadWriteLock(lockInfo.getName());
        // 该锁是否被当前线程持有
        if (rLock.writeLock().isHeldByCurrentThread()) {
            rLock.writeLock().unlockAsync();
        }
        lockInfoThreadLocal.remove();
    }
}
